/**
 * 
 */
package com.easidea.tim.dao.inventory;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.LogicalExpression;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springside.core.dao.extend.HibernateEntityExtendDao;

import com.easidea.tim.dao.saleorder.SaleOrderDao;
import com.easidea.tim.entity.commodity.Product;
import com.easidea.tim.entity.inventory.Storage;
import com.easidea.tim.entity.saleorder.SaleOrder;
import com.easidea.tim.util.Page;

/**
 * @author Harrison
 *
 */
public class StorageDao extends HibernateEntityExtendDao<Storage> {
	
	private double sampleStorageMeterLimitation = 0; //系统设定的剪样库存最低阀值
	private SaleOrderDao saleOrderDao;
	
	public List<Storage> getStorageBySaleOrderId(Long saleOrderId) {
		List<Storage> list = null;
		if(saleOrderId != null){
			SaleOrder so = saleOrderDao.get(saleOrderId);
			if(so != null)
				list = (List<Storage>)getStorageBySaleOrder(so);
		}
		return list;
	}
	
	public List<Storage> getStorageBySaleOrder(SaleOrder so){
		List<Storage> list = null;
		if (so != null
				&& so.getFlowNo() != null
				&& so.getStatus().shortValue() >= Short.valueOf(SaleOrder.order_staus_complete).shortValue()
				&& so.getStatus().shortValue() != Short.valueOf(SaleOrder.order_staus_over).shortValue()) {
				//有效的销售订单及合法的状态
			Criteria cte = createUnDeletedCriteria();
			cte.add(Restrictions.eq("chargedFlowNo", so.getFlowNo()));
			cte.add(Restrictions.eq("chargeFlag", true));
			cte.addOrder(Order.asc("product.id"));
			list = (List<Storage>)cte.list();
		}
		return list;
	}
	
	/**
	 * 根据布品信息、布品米数长度、是否剪样判断是否存在相应的库存
	 * @param product
	 * @param meterNum
	 * @param sampleFlag
	 * @return 有库存的数据
	 */
	public List<Storage> getStorages(Product product, Double[] meterNum, Boolean sampleFlag) {
		if(product != null){
			Criteria cte = createUnDeletedCriteria();
			cte.createAlias("product", "product");
			cte.add(Restrictions.eq("product.dummyFlag", false)); //挂板支持
			if(StringUtils.isNotBlank(product.getName()))cte.add(Restrictions.eq("product.name", product.getName()));
			if(StringUtils.isNotBlank(product.getColorCode()))cte.add(Restrictions.eq("product.colorCode", product.getColorCode()));
			if(product.getId() != null) cte.add(Restrictions.eq("product.id", product.getId()));
			if(sampleFlag != null && sampleFlag)
				cte.add(Restrictions.eq("sampleFlag", sampleFlag));
			else{
				// 非剪样时，则根据填写的米数去提取
				cte.add(Restrictions.eq("sampleFlag", false));
				if(meterNum != null && meterNum.length > 0)cte.add(Restrictions.in("meterNum", meterNum));
			}
			cte.add(Restrictions.eq("chargeFlag", false));
			return (List<Storage>)cte.list();
		}
		return null;
	}

	/**
	 * 根据剪样名称和色号提取库存数据
	 * @param name
	 * @param colorCode
	 * @return
	 */
	public List<Storage> getSampleStorage(String name, String colorCode){
		if(StringUtils.isNotBlank(name) && StringUtils.isNotBlank(colorCode)){
			Criteria cte = createUnDeletedCriteria();
			cte.createAlias("product", "product");
			cte.add(Restrictions.eq("product.name", name.trim()));
			cte.add(Restrictions.eq("product.colorCode", colorCode.trim()));
			cte.add(Restrictions.eq("sampleFlag", true));
			return (List<Storage>)cte.list();
		}
		return null;
	}
	
	/**
	 * 根据产品ID提取剪样库存 
	 * @param productId
	 * @return
	 */
	public List<Storage> getSampleStorage(Long productId){
		if(productId != null){
			Criteria cte = createUnDeletedCriteria();
			cte.add(Restrictions.eq("product.id", productId));
			cte.add(Restrictions.eq("sampleFlag", true));
			return (List<Storage>)cte.list();
		}
		return null;
	}

	/**
	 * 根据库存数据列表，获得对应已记录的库存数据
	 * @param stoList
	 * @param isMatchMeterNum
	 * @return
	 */
	public List<Storage> list(List<Storage> stoList, boolean isMatchMeterNum){
		Criteria cte = createUnDeletedCriteria();
		cte.createAlias("product", "product");
		cte.add(Restrictions.eq("product.dummyFlag", false)); //挂板支持
//		cte.add(Restrictions.eq("usedFlag", false));
		Criterion cri = null;
		for(short i = 0;i<stoList.size();i++){
			Storage st = stoList.get(i);
			Product p = st.getProduct();
			
			Criterion nameCt = Restrictions.eq("product.name", p.getName());
			Criterion colorCt = Restrictions.eq("product.colorCode", p.getColorCode());
			Criterion sfCt = Restrictions.eq("sampleFlag", st.getSampleFlag());
			
			LogicalExpression ncLE = Restrictions.and(nameCt, colorCt);
			LogicalExpression allLE = null;
			
			if(isMatchMeterNum){
				Criterion meterCt = Restrictions.eq("meterNum", st.getMeterNum());
				LogicalExpression msLE = Restrictions.and(sfCt, meterCt);
				allLE = Restrictions.and(ncLE,msLE);
			}else{
				allLE = Restrictions.and(ncLE, sfCt);
			}
			
			if(i == 0){
				cri = allLE;
			}else{
				cri = Restrictions.or(cri, allLE);
			}
		}
		cte.add(cri);
		return (List<Storage>)cte.list();
	}
	
	/**
	public String Incharge(String productName, String colorCode, String soflowNo, Float...meterNums){
		String result = "";
		Set chargeset = storageService.inChargeStorage(productName, colorCode, soflowNo, meterNums);
		Iterator<Short> ir = chargeset.iterator();
		while(ir.hasNext()){
			result = new Short(ir.next()).toString();
		}
		return result;
	}
	**/
	
	/**
	 * 获取查询库存的数据脚本
	 */
	private String genPageQueryHql(String productName,String colorCode, Boolean sampleFlag, Boolean isIncludeChargedStorage){
		StringBuffer  hqlBF = new StringBuffer("SELECT  p.id AS product_id,  COUNT(st.id) AS pi_num, SUM(st.meterNum) AS meter_num, p.name AS product_name, p.colorCode AS color_code, st.sampleFlag AS sample_flag, st.chargeFlag as charge_flag"
			+ " FROM  " + Storage.class.getName() + " AS st , " + Product.class.getName() + " AS p WHERE st.product.id = p.id AND p.dummyFlag = false AND st.deleted = 0");//挂板支持
		
		if(productName != null && productName.trim().length() > 0){
			hqlBF.append(" AND p.name = '" + productName + "'");
		}
		
		if(colorCode != null && colorCode.trim().length() > 0){
			hqlBF.append(" AND p.colorCode = '" + colorCode + "'");
		} 
		
		if(sampleFlag != null){
			hqlBF.append(" AND st.sampleFlag = " + sampleFlag );
		}
		
		if(isIncludeChargedStorage != null && !isIncludeChargedStorage){
			hqlBF.append(" AND st.chargeFlag = " + isIncludeChargedStorage);
		}
		
		hqlBF.append(" GROUP BY p.name, p.colorCode");
		
		return hqlBF.toString();
	}
	
	/**
	 * 查询库存列表，如果page对象是空，则返回全部库存数据
	 * @param productName
	 * @param colorCode
	 * @param sampleFlag
	 * @param page
	 * @return
	 */
	public Map<String, Object> pagedQueryStorageList(String productName,String colorCode, 
			Boolean sampleFlag, Page page, Boolean isIncludeChargedStorage){
		Query query = createQuery(genPageQueryHql(productName,colorCode,sampleFlag, isIncludeChargedStorage));
		List<Object[]> objList = query.list();
		Integer totalCounts = objList == null ? 0 : objList.size();
		
		Map<String, Object> rtnMap = new HashMap<String, Object>();
		query = null;
		query = createQuery(genPageQueryHql(productName,colorCode,sampleFlag, isIncludeChargedStorage));

		List<Object[]> dataList = null;
		
		if(page != null){
			int index = Page.getStartOfPage(page.getCurrentPageNo(), page.getPageSize());
			query.setFirstResult(index);
			query.setMaxResults(page.getPageSize());		
			dataList = query.list(); 
			
			rtnMap.put("totalCounts",totalCounts);
			rtnMap.put("startIndex",index);
			
		}else{
			dataList = query.list(); 
		}
		rtnMap.put("data", dataList);
		return rtnMap;
	}
	
	/**
	 * 取消填充
	 * 
	 * @param productName
	 * @param colorCode
	 * @param soFlowNo
	 */
	public void cancelChargedStorage(String productName, String colorCode,String soFlowNo){
		List<Storage> chargedList = listChargedStorage(productName, colorCode, soFlowNo);
		if(chargedList != null && chargedList.size()>0){
			for(Storage st : chargedList){
				if(st != null && st.getId() != null){
					st.setChargeFlag(false);
					st.setChargedFlowNo(null);
				}
			}
		}
	}
	
	/**
	 * 查找库存数据中被填充的数据
	 * @param productName
	 * @param colorCode
	 * @param soFlowNo
	 * @return
	 */
	private List<Storage> listChargedStorage(String productName, String colorCode,String soFlowNo){
		List<Storage> st = null;
		if(productName != null && colorCode != null && soFlowNo != null){
			Criteria cte = createUnDeletedCriteria();
			cte.createAlias("product", "product");
			cte.add(Restrictions.eq("product.name", productName));
			cte.add(Restrictions.eq("product.colorCode", colorCode));
			cte.add(Restrictions.eq("product.dummyFlag", false)); //挂板支持
			cte.add(Restrictions.eq("chargeFlag",true));
			if(StringUtils.isNotBlank(soFlowNo))cte.add(Restrictions.eq("chargedFlowNo", soFlowNo));
			st = cte.list();
		}
		return st;
	}
	
	/**
	 * 取消填充
	 * 
	 * @param productName
	 * @param colorCode
	 * @param soFlowNo
	 */
	public void cancelChargedStorageByFlowNo(String soFlowNo){
		List<Storage> chargedList = listChargedStorageBysoFlowNo(soFlowNo);		
		for(Storage st : chargedList){
			if(st != null && st.getId() != null){
				st.setChargeFlag(false);
				st.setChargedFlowNo(null);
			}
		}
	}
	
	
	/**
	 * 查找库存数据中被填充的数据
	 * @param productName
	 * @param colorCode
	 * @param soFlowNo
	 * @return
	 */
	private List<Storage> listChargedStorageBysoFlowNo(String soFlowNo){
		List<Storage> st = null;
		if(soFlowNo != null){
			Criteria cte = createUnDeletedCriteria();
			cte.add(Restrictions.eq("chargeFlag",true));
			cte.add(Restrictions.eq("chargedFlowNo", soFlowNo));
			st = cte.list();
		}
		return st;
	}
	
	/**
	 * 获取库存总额
	 * @return
	 */
	public Map<String, Double> getStorageSummary(){
		String hql = "SELECT COUNT(st.id) AS piNum , SUM(st.meterNum) AS meterNum FROM "+ Storage.class.getName() + " AS st WHERE st.deleted = 0";
		Query query = createQuery(hql);
		List<Object[]> objList = query.list();
		Object[] value = objList.get(0);
		Double piNum = ((Long)value[0]).doubleValue();
		Double meterNum = (Double)value[1];
		
		Map<String, Double> rtn = new HashMap<String, Double>();
		rtn.put("piSummary", piNum);
		rtn.put("meterSummary", meterNum);
		return rtn;
	}
	
	
	/**
	 * 备货填充，根据布品名、布品色号、传入的米数数组进行备货检查，同时对于备货成功的数据，进行备货登记
	 * <p>
	 * 注：相关meterNum数据不能是剪样数据
	 * </p>
	 * 
	 * @param productName
	 * @param colorCode
	 * @param soFlowNo
	 *            销售单据编号
	 * @param meterNums
	 * @return short 类型数据，长度为1且值为<code>-1</code>表示无异常数据，否则为当前库存数据中未出现的数据
	 */
	public Set<Short> inChargeStorage(String productName, String colorCode,
			String soflowNo, Double... meterNums) {
		Set<Short> rtnset = new HashSet<Short>();
		
		boolean isSample = isSampleOrder(soflowNo);
		List<Storage> stList = listExistStorage(productName, colorCode, isSample, meterNums); // 查找合适的库存

		if (stList != null && stList.size() > 0 ) {
			Object[][] dataArray = new Object[stList.size()][2];// 准备被查询数组
			for (short i = 0; i < stList.size(); i++) {
				dataArray[i][0] = i;
				dataArray[i][1] = stList.get(i).getMeterNum();
			}// 填充被查询数组

			HashSet<Short> usedIndex = new HashSet<Short>();

			for (short i = 0; i < meterNums.length; i++) {
				Double required = meterNums[i];
				boolean t = arrangeContainsIndex(dataArray, required, usedIndex); // 是否包含合适数据的结果
				if (!t) {
					// 查询结果中，未包含所查询的数据
					short index = (short) (i + (short) 1);
					rtnset.add(index); // 添加到返回数据集合中，供前台进行对应index数据的提醒
				}
			}

			/**
			 * --------- modified by Harrison on 2010-5-24 for incharge index
			 * not fit for the query data index ---
			 */
			if (rtnset.size() == 0) {
				// 填充的数据全部都找到
				/*
				 * 进行库存数据更新 -- 锁库存
				 */
				Short[] usedIndexArray = new Short[usedIndex.size()];
				usedIndexArray = usedIndex.toArray(usedIndexArray);
				for (short i = 0; i < usedIndexArray.length; i++) {
					Storage st = stList.get(usedIndexArray[i]);
					if (st != null && !st.getChargeFlag()) {
						st.setChargeFlag(true);
						if(StringUtils.isNotBlank(soflowNo))st.setChargedFlowNo(soflowNo);
						this.getHibernateTemplate().update(st);
					}
				} // 锁库
				rtnset.add(Short.parseShort("-1")); // 构造返回数据
			}

			// }
		}

		return rtnset;
	}

	/**
	 * 根据传入的销售订单flowNo判断是否剪样订单
	 * @param soflowNo
	 * @return
	 */
	private boolean isSampleOrder(String soflowNo) {
		if(StringUtils.isNotBlank(soflowNo)){
			SaleOrder so = saleOrderDao.getSaleOrderByFlowNo(soflowNo);
			if(so != null && StringUtils.isNotBlank(so.getOrderType()) 
					&& (
							so.getOrderType().equalsIgnoreCase(SaleOrder.order_type_sample) 
							||  so.getOrderType().equalsIgnoreCase(SaleOrder.order_type_sample_return)
						) )
			{
				return true;
			}
		}
		return false;
	}

	/**
	 * 查询库存中符合要求的所有数据
	 * 
	 * @param productName
	 * @param colorCode
	 * @param meterNums
	 * @return
	 */
	private List<Storage> listExistStorage(String productName,
			String colorCode, boolean isSample, Double... meterNums) {
		List<Storage> stList = null;
		if (productName != null && productName.trim().length() > 0
				&& colorCode != null && colorCode.trim().length() > 0
				&& meterNums != null && meterNums.length > 0) {
			Criteria cte = createUnDeletedCriteria();
			cte.createAlias("product", "product");
			cte.add(Restrictions.eq("product.name", productName));
			cte.add(Restrictions.eq("product.colorCode", colorCode));
			cte.add(Restrictions.eq("product.dummyFlag", false)); //挂板支持
			cte.add(Restrictions.eq("chargeFlag", false));
			cte.add(Restrictions.isNull("chargedFlowNo"));
			cte.add(Restrictions.in("meterNum", meterNums));
			cte.add(Restrictions.eq("sampleFlag", isSample));
			stList = cte.list();
		}
		return stList;
	}
	
	/**
	 * 获得查询数据在数组中的位置
	 * 
	 * @param dataArray
	 *            被查询数组，其结构是n行2列的数据格式，其中第一列是该数据在整体List中的索引位，第二列是具体需要查询的数值。
	 * @param value
	 *            要查询的数值
	 * @param usedIndex
	 *            要查询数值在被查询数组中的位置
	 * 
	 * @return 是否查询到合适的数据
	 */
	private boolean arrangeContainsIndex(Object[][] dataArray, Double value,
			HashSet<Short> usedIndex) {
		boolean t = false;
		if (dataArray != null && value != null && usedIndex != null) {
			for (short i = 0; i < dataArray.length; i++) {
				Short index = (Short) dataArray[i][0]; // 获得索引位
				Double num = (Double) dataArray[i][1]; // 获得业务数值
				if (num.doubleValue() == value.doubleValue()
						&& !usedIndex.contains(index)) {
					usedIndex.add(index);
					t = true;
					break; // 中断当前的查找
				}
			}
		}
		return t;
	}
	
	
	/**
	 * @return the saleOrderDao
	 */
	public SaleOrderDao getSaleOrderDao() {
		return saleOrderDao;
	}

	/**
	 * @param saleOrderDao the saleOrderDao to set
	 */
	public void setSaleOrderDao(SaleOrderDao saleOrderDao) {
		this.saleOrderDao = saleOrderDao;
	}

	/**
	 * 根据采购订单提取库存锁库数据，为采购退货使用
	 * @param flowNo
	 * @return
	 */
	public List<Storage> getStorageByPOFlowNo(String flowNo) {
		if(StringUtils.isNotBlank(flowNo)){
			Criteria cte = createUnDeletedCriteria();
			cte.add(Restrictions.eq("chargeFlag",true));
			cte.add(Restrictions.eq("chargedFlowNo", flowNo));
			return (List<Storage>) cte.list();
		}
		return null;
	}

	/**
	 * 检查剪样库存是否低于剪样最低阀值数据
	 * @param name
	 * @param colorCode
	 * @return
	 */
	public boolean validateSampleStorageLimitaion(String name, String colorCode){
		List<Storage> sampleStList = this.getSampleStorage(name, colorCode);
		if(sampleStList != null && sampleStList.size() == 1){
			Storage smpStorage = sampleStList.get(0);
			if(smpStorage.getMeterNum().doubleValue() <= getSampleStorageMeterLimitation())
				return true;
		}
		return false;
	}
	
	/**
	 * @return the sampleStorageMeterLimitation
	 */
	public double getSampleStorageMeterLimitation() {
		return sampleStorageMeterLimitation;
	}

	/**
	 * @param sampleStorageMeterLimitation the sampleStorageMeterLimitation to set
	 */
	public void setSampleStorageMeterLimitation(double sampleStorageMeterLimitation) {
		this.sampleStorageMeterLimitation = sampleStorageMeterLimitation;
	}
}
